package pl.edu.mimuw.irs.rcp.controller.editor.report;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

import pl.edu.mimuw.irs.core.model.analysis.History;
import pl.edu.mimuw.irs.core.model.analysis.Time;
import pl.edu.mimuw.irs.core.model.design.resource.Resource;

public class ResultsTable {

	protected static final int PAGE_SIZE = 1000000;
	
	// *** Properties
	
	public static final String SORTED = "SORTED";
	
	// *** Attributes

	private TableViewer viewer;
	private TableColumn runNoColumn;
	private TableColumn timeColumn;
	private TableColumn costColumn;
	private TableColumn multiColumn;
	private List<History> originalList;
	private List<History> currentList;
	public TableViewer getViewer() {
		return viewer;
	}
	public List<History> getOriginalList() {
		return originalList;
	}
	public List<History> getCurrentList() {
		if (currentList == null) currentList = new LinkedList<History>();
		return currentList;
	}
	
	// *** Constructors

	public ResultsTable(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
		
		createPartControl(parent);
	}
	
	// *** Methods
	
	private void createPartControl(Composite parent) {
		final Table table = viewer.getTable();
		table.setLinesVisible (true);
		table.setHeaderVisible (true);
		//gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
		//gridData.horizontalSpan = 2;
		//gridData.heightHint = PAGE_SIZE;
		//table.setLayoutData(gridData);
		
		String[] titles = new String[] { "Run no.", "Total time", "Total cost", "Time * Cost", "1st busiest", "2nd busiest", "3rd busiest" };
		
		runNoColumn = new TableColumn(table, SWT.NONE); runNoColumn.setText(titles[0]); runNoColumn.setWidth(40);
		timeColumn = new TableColumn(table, SWT.NONE); timeColumn.setText(titles[1]); timeColumn.setWidth(75);
		costColumn = new TableColumn(table, SWT.NONE); costColumn.setText(titles[2]); costColumn.setWidth(75);
		multiColumn = new TableColumn(table, SWT.NONE); multiColumn.setText(titles[3]); multiColumn.setWidth(75);
		for (int i = 4; i < titles.length; i++) {
			TableColumn column = new TableColumn(table, SWT.NONE);
			column.setText(titles [i]);
			column.setWidth(100);
		}

		table.addListener(SWT.SetData, new Listener() {
			public void handleEvent(Event e) {
				TableItem item = (TableItem) e.item;
				int index = table.indexOf(item);
				History history = getCurrentList().get(index);
				if (history == null) return;
				
				item.setData(history);
				
				Integer time = history.getTimestamp().getValue();
				Integer cost = history.getTotalUsageCost();
				Integer multi = time * cost;

				item.setText(0, String.valueOf(getOriginalList().indexOf(history) + 1));
				item.setText(1, time.toString());
				item.setText(2, cost.toString());
				item.setText(3, multi.toString());

				List<Entry<Resource, Time>> busiest = history.getBusiest();
				
				if (busiest.size() > 0) {
					Entry<Resource, Time> busiest1 = busiest.get(0);
					item.setText(4, busiest1.getKey() + "=" + busiest1.getValue().getValue());
				}
				if (busiest.size() > 1) {
					Entry<Resource, Time> busiest2 = busiest.get(1);
					item.setText(5, busiest2.getKey() + "=" + busiest2.getValue().getValue());
				}
				if (busiest.size() > 2) {
					Entry<Resource, Time> busiest3 = busiest.get(2);
					item.setText(6, busiest3.getKey() + "=" + busiest3.getValue().getValue());
				}
			}
		});

		
		
		makeSortable(table);
		
	}

	private void makeSortable(final Table table) {
		Listener sortListener = new Listener() {
			public void handleEvent(Event e) {
				// determine new sort column and direction
				TableColumn sortColumn = table.getSortColumn();
				TableColumn currentColumn = (TableColumn) e.widget;
				int dir = table.getSortDirection();
				if (sortColumn == currentColumn) {
					dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
				} else {
					table.setSortColumn(currentColumn);
					dir = SWT.UP;
				}
				table.setSortDirection(dir);
				
				sortCurrentList();
				
				// update data displayed in table
				table.clearAll();
			}
		};
		runNoColumn.addListener(SWT.Selection, sortListener);
		timeColumn.addListener(SWT.Selection, sortListener);
		costColumn.addListener(SWT.Selection, sortListener);
		multiColumn.addListener(SWT.Selection, sortListener);
		table.setSortColumn(timeColumn);
		table.setSortDirection(SWT.UP);

	}

	protected void sortCurrentList() {
		TableColumn currentColumn = getViewer().getTable().getSortColumn();
		int dir = getViewer().getTable().getSortDirection();
		
		// sort the data based on column and direction
		if (currentColumn == runNoColumn) {
			currentList = new ArrayList<History>(getOriginalList());
			if (dir == SWT.DOWN) Collections.reverse(getCurrentList());
		} else if (currentColumn == timeColumn) {
			Collections.sort(getCurrentList(), new TimeComparator(dir));
		} else if (currentColumn == costColumn) {
			Collections.sort(getCurrentList(), new CostComparator(dir));
		} else if (currentColumn == multiColumn) {
			Collections.sort(getCurrentList(), new MultiComparator(dir));
		} else return; // Skip if not sortable column was selected
	}
	
	public void loadHistory(List<History> list) {

		final Table table = viewer.getTable();
		
		originalList = list;
		currentList = new ArrayList<History>(list);
		
		table.clearAll();
		table.setItemCount(Math.min(PAGE_SIZE, currentList.size()));
		
		sortCurrentList();
	}
	
	public abstract class HistoryComparator implements Comparator<History> {
		
		private int direction;
		public int getDirection() {
			return direction;
		}
		
		public HistoryComparator(int direction) {
			this.direction = (direction == SWT.UP ? 1 : -1);
		}
		
		@Override
		public int compare(History arg0, History arg1) {
			return direction * compareAsc(arg0, arg1);
		}

		protected abstract int compareAsc(History arg0, History arg1);
		
	}
	
	public class TimeComparator extends HistoryComparator {

		public TimeComparator(int direction) {
			super(direction);
		}

		@Override
		public int compareAsc(History arg0, History arg1) {
			return arg0.getTimestamp().compareTo(arg1.getTimestamp());
		}
	}
	
	public class CostComparator extends HistoryComparator {

		public CostComparator(int direction) {
			super(direction);
		}

		@Override
		public int compareAsc(History arg0, History arg1) {
			return arg0.getTotalUsageCost() - arg1.getTotalUsageCost();
		}
	}

	public class MultiComparator extends HistoryComparator {

		public MultiComparator(int direction) {
			super(direction);
		}

		@Override
		public int compareAsc(History arg0, History arg1) {
			int x = arg0.getTotalUsageCost() * arg0.getTimestamp().getValue();
			int y = arg1.getTotalUsageCost() * arg1.getTimestamp().getValue();
			return x - y;
		}
	}
}
